home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-11-09 | 27.0 KB | 1,193 lines |
- //
- // Cassandra.m
- // Copyright (c) 1988, 1989, 1990, 1991, 1992 by Jiro Nakamura
- // All rights reserved
- //
- // Main control object of Cassandra. Routes most calls to their proper places
- // and handles alarm control.
- //
- // by Jiro Nakamura (jiro@shaman.com)
- //
- // RCS Information
- // Revision Number-> $Revision: 2.19 $
- // Last Revised-> $Date: 92/11/10 00:50:10 $
- //
- static char authorid[] = "$Author: jiro $";
- static char rcsid[] = "$Id: Cassandra.m,v 2.19 92/11/10 00:50:10 jiro Exp Locker: jiro $";
- static char copyrightid[] =
- "Copyright (C) 1988, 1989, 1990, 1991 by Jiro Nakamura. "
- "All Rights Reserved.";
-
- #import <stdio.h>
- #import <libc.h>
- #import <time.h>
- #import <sys/file.h>
- #import <strings.h>
- #import <appkit/Form.h>
- #import <appkit/Button.h>
- #import <appkit/Panel.h> /* for NXRunAlertPanel() */
- #import <appkit/publicWraps.h> /* for NXBeep( ) */
- #import <appkit/Application.h> /* for NX_MODALRESPTHRESHOLD */
- #import <appkit/PageLayout.h>
- #import <dpsclient/wraps.h>
- #import <soundkit/Sound.h>
- #import <bsd/dev/m68k/evsio.h> /* For screen handling */
-
- #import "Cassandra.h"
- #import "Event.h"
- #import "Global.h"
- #import "misc.h"
- #import "calendar.h"
- #import "EventLog.h"
- #import "Notepad.h"
- #import "Overview.h"
- #import "Today.h"
-
- #define WHENREADY -1.0 // for startAlarmTimedEntry
- #define NOW 0.0
-
- #define MAXSECONDS (24 * 60 * 60) // 24 hours in seconds
-
- char *getlogin(); // This isn't defined anywhere....
- // NeXT, get on your feet!
-
- @implementation Cassandra
-
- // We override new in order to set the delegate of the application object
- // to itself. This allows the appDidInit: and appDidHide: delegate methods
- // to be invoked properly.
- + new
- {
-
- #ifdef DEBUG
- fprintf(stderr,"Cassandra being created.\n");
- #endif
-
- self = [super new];
- [self setDelegate:self];
-
- alarmFree = TRUE;
- snooze = 0;
- secondsUntilEvent = 0.0;
- queueModified = TRUE;
- return self;
- }
-
- // appDidInit is called as the first thing in the run loop of the
- // application. At this point, everything is created, but we haven't entered
- // the event loop yet. appDidInit first loads the global variables in
- // from the defaults database, then appDidInit creates a new instance
- // Clock, and
- // makes it a subview of the application icon window (obtained through
- // the appIcon method of Application). It then goes about and sets the
- // lockFile for cassandra, opening the windows we need, etc.
- - appDidInit: app
- {
- FILE *lFile; // lockFile file descriptor
- char line1[127], tmpFile[129];
- char tmp[256];
- NXRect cvFrame; // contentView frame
- id applicationIcon = [NXApp appIcon]; // Our beloved icon
-
- #ifdef DEBUG
- fprintf(stderr,"Cassandra did initialize."
- " (From Cassandra.m)\n");
- #endif
-
- now = *timeNow(); // Set the time
- [global load:self]; // Let's load the global variables
-
- queueModified = YES; // Make sure queue gets re-read
-
- // Check for lockfile, if none, create one. If one, ask user
- // what he/she wants to do.
- strcpy(lockFile,[global eventFile]); // "eventFile" + ".lck"
- strcat(lockFile,".lck");
- if( access( lockFile, F_OK ) == 0) // if it exists
- {
- lFile = fopen(lockFile,"r");
- fgets(line1,128,lFile);
- fclose(lFile);
-
- if( NXRunAlertPanel("Event File in Use",line1,
- "Quit","Open Anyway",NULL) == 1)
- exit(1);
- }
-
- // Ok. None exists. Create the lockFile giving the current
- // username and time.
- lFile = fopen( lockFile, "w");
- fprintf(lFile, "The Event file is still in use. "
- "It was opened by %s on %s.\n"
- "Do you want to open it anyway?",
- NXUserName(),
- ascMyTime( (struct tm *)timeNow(),
- [global showSeconds],
- [global militaryTime]));
- fclose(lFile);
-
- // Check to see if there is a compressed EventFile
- strcpy( tmpFile, [global eventFile]);
- strcat( tmpFile, ".Z");
- if( access([global eventFile], R_OK) != 0 &&
- access( tmpFile, R_OK) == 0) // It exists
- {
- sprintf( tmp, "/usr/ucb/uncompress %s", tmpFile);
- #ifdef DEBUG
- fprintf( stderr, "%s:", PROGNAME, tmp);
- #endif
- system( tmp);
- }
-
- // Set up the clock icon
- // This is from ClockApp (used w/ author's permission)
- [[applicationIcon contentView] getFrame:&cvFrame];
- NXInsetRect(&cvFrame, 3.0, 3.0); //let 's not touch the border
- clockView = [Clock newFrame:&cvFrame];
-
- [[applicationIcon contentView] addSubview:clockView];
- [self defaultsDidChange:self];
- [applicationIcon display];
- // then, set the target and action of Clock so we can use it.
- [clockView setTarget: self];
- [clockView setAction: @selector(tick:)];
- [self updateClockViewMessage: self];
-
-
- // If we should source .cassandra/login at login-time
- if( [global sourceLoginOnLaunch] && [global autoLaunched])
- {
- sprintf(tmp, "/bin/sh %s",[global sourceLoginFile] );
- #ifdef DEBUG
- fprintf( stderr, "%s:", PROGNAME, tmp);
- #endif
- system( tmp );
- }
-
-
- // If we are opening the Overview at launch
- if( [global overviewOnLaunch])
- [overview open: self];
-
- // If we are opening the Log at launch
- if( [global eventLogOnLaunch])
- [eventLog open:self];
-
- // If we are opening the Notepad at launch
- if( [global notepadOnLaunch])
- [notepad open:self];
-
- // If we are opening Today at launch
- if( [global todayOnLaunch])
- [today open:self];
-
- // If we are opening Week at launch
- if( [global weekOnLaunch])
- [week open:self];
-
- [self startAlarmTimedEntry: NOW];
-
- // If we should hide ourselves at launch...
- if( [global hideOnLaunch] && [global autoLaunched] )
- [NXApp perform: @selector(hide:)
- with: self
- afterDelay: 1
- cancelPrevious: NO];
-
- return self;
- }
-
- //
- // appDidHide is called if the user hides the application.
- // appDidUnhide is called when the user unhides the application.
- // These aren't implemented (just yet).
- //
- - appDidHide
- {
-
- return self;
- }
-
- - appDidUnhide
- {
- [overview timeUpdate:self];
- [today timeUpdate: self];
- [week timeUpdate: self];
-
- if( timeNow()->tm_mday != now.tm_mday)
- {
- [today update];
- [overview monthUpdate: self];
- now = *timeNow();
- }
- return self;
- }
-
- //
- // Cassandra is about to quit. First, remove the lockfile,
- // the close all the windows (they will save their positions
- // automatically) and then quit.
- //
- - cassandraWillQuit:sender;
- {
- char tmp[256];
-
- unlink( lockFile); // Remove lockFile before quiting
-
- if( [global compressEvents])
- {
- sprintf( tmp, "/usr/ucb/compress -f %s&", [global eventFile]);
- #ifdef DEBUG
- fprintf(stderr,"Compressing event file...\n");
- fprintf(stderr, "%s:", PROGNAME, tmp);
- #endif
-
- system( tmp);
- }
-
- // If we should source .cassandra/logout at logout-time
- if( [global sourceLoginOnLaunch] && [global autoLaunched] )
- {
- sprintf(tmp, "/bin/sh %s",[global sourceLogoutFile] );
- #ifdef DEBUG
- fprintf( stderr, "%s:", PROGNAME, tmp);
- #endif
- system( tmp );
- }
-
- if( [overview isVisible])
- [overview performClose:self];
- if( [global isVisible])
- [global performClose:self];
-
- if( [notepad isVisible])
- [notepad performClose:self];
- if( [eventLog isVisible])
- [eventLog performClose:self];
- if( [today isVisible])
- [today performClose: self];
- if( [week isVisible])
- [week performClose: self];
- if( [addEventPanel isVisible])
- [addEventPanel performClose: self];
- if( [editEventPanel isVisible])
- [editEventPanel performClose: self];
-
- return self;
- }
-
- //
- // We want to catch the powerOff and logOut messages from the WM
- // The user should manually quit Cassandra or else window
- // positions will NOT be saved.
- //
- - appPowerOffIn: (int) ms andSave: (int) aFlag
- {
- // We are powering off, oh no....
- if( aFlag == YES) // If we are allowed to save, then
- [self cassandraWillQuit: self];
- else
- unlink( lockFile); // At least remove the lockFile
- // before quiting
-
- return self;
- }
-
- //
- // Brings up the information panel.
- //
- - info:sender
- {
- if (!infoPanel)
- {
- infoPanel=[self loadNibSection:"InfoPanel.nib" owner:self withNames:NO];
- }
- [infoPanel orderFront:self];
- return self;
- }
-
- //
- // Brings up the help panel.
- //
- - help:sender
- {
- if (!helpPanel)
- {
- helpPanel = [self loadNibSection:"HelpPanel.nib" owner:self withNames:NO];
- }
- [helpPanel orderFront:self];
- return self;
- }
-
- //
- // Brings up the Calculator window.
- //
- - calculator:sender
- {
- if( calculatorWindow == nil)
- {
- calculatorWindow = [self loadNibSection: "Calculator.nib"
- owner:self withNames:NO];
- }
- [calculatorWindow makeKeyAndOrderFront:self];
- return self;
- }
-
-
- // quit is called by the quit button on the main menu.
- // checks to see if the user really wants to quit, then invokes
- // the terminate method of itself if she or he does.
- - quit: sender
- {
-
- #ifdef ASK_IF_QUITTING
- if( NXRunAlertPanel(NULL,"Really quit?",
- "Quit","Cancel",NULL) == 1)
- {
- [self cassandraWillQuit:self];
- [NXApp terminate: self];
- }
- #else
- [self cassandraWillQuit:self];
- [NXApp terminate: self];
- #endif
-
- return nil;
- }
-
- // closeKeyWindow: is called by the Close button on the Window submenu
- // it closes the key window (naturally).
- - closeKeyWindow:sender
- {
- [[self keyWindow] performClose:self];
- return self;
- }
-
- // saveKeyWindow: is called by the Save button on the Window submenu
- // it saves the key window (naturally).
- - saveKeyWindow:sender
- {
- if( [[self keyWindow] respondsTo: @selector(save)])
- [[self keyWindow] save];
- return self;
- }
-
-
- // miniaturizeKeyWindow: is called by the Minituarize button on the
- // Window submenu, it miniaturizes the key window (naturally).
- - miniaturizeKeyWindow:sender
- {
- [[self keyWindow] performMiniaturize:self];
- return self;
- }
-
- // Runs the page layout panel
- - runPageLayout: sender
- {
- [[PageLayout new] runModal];
- return self;
- }
-
- - print: sender
- {
- id mainWin = [NXApp keyWindow];
-
- if( mainWin == nil )
- NXBeep();
-
- return [mainWin printPSCode: sender];
- }
-
-
- // =======================================================
- // Alarm Routines
- //========================================================
- // Ideally, these should be in a separate class.
- // But efficiency dictates this method.
- // They check the queue to see when the next event is, plant
- // a timer entry for that time, then when it calls, bring
- // up the alarm panel, play the jingle, etc., handle the
- // anniversary events/snooze events/etc.
-
- - alarmStart:sender
- {
- Event *ev;
-
- #ifdef DEBUG
- fprintf(stderr,"Alarm starting\n");
- #endif
-
- // Wake up an alarm is starting
- [NXApp activateSelf: NO]; // Let's activate ourself!
- [Sound getVolume: &oldVolumeLeft:&oldVolumeRight];
-
- ev = [Event newAt:[global eventFile]];
- [ev firstEvent]; // Read the first event
-
- if( [alarmPanel isVisible]) // If it is visible
- { // then let us just
- if( [ev playAlarm] && alarmFree && ![ev runCommand])
- // play the alarm sound
- [self playAlarm: [ev alarmSound]];
-
- [[self stopAlarmTimedEntry] startAlarmTimedEntry: 3*60.0];
- [ev free];
- return self; // repeat after three minutes
- }
-
- if( [ev showMessage])
- {
- [alarmPanelTime setStringValue:
- ascMyTime([ev time], NOSEC,
- [global militaryTime]) at:0];
- [alarmPanelMessage setStringValue : [ev message] at:0];
- [alarmPanelNextEvent setStringValue: ascMyTime(
- fixAnniversary([ev time], [ev anniversary],
- [ev annvSpecial]),
- NOSEC, [global militaryTime]) at: 0];
-
- if( [ev snoozeNo] > 1)
- [snoozeButton setEnabled : TRUE];
- else
- [snoozeButton setEnabled : FALSE];
-
- [snoozeButton setState: 0];
- [okButton setState: 0];
-
- [alarmPanel makeKeyAndOrderFront: self];
- NXPing();
- }
-
- #ifdef DEBUG
- fprintf(stderr, "Starting alarm with: %s\n : %s",
- ascMyTime([ev time], NOSEC, [global militaryTime]),
- [ev message]);
- #endif
-
- if( alarmFree && [ev playAlarm] && ![ev runCommand] )
- [self playAlarm: [ev alarmSound]];
- else
- {
- #ifdef DEBUG
- fprintf(stderr,"Alarm is not free or no alarm.....\n");
- #endif
- if( [ev runCommand] )
- system( [ev alarmSound] );
-
- }
-
- [ev free];
- [self nextSnoozeAlarm];
-
- return self;
- }
-
- - playAlarm: (char *) alarmSound
- {
- int error;
-
- // From 1.0 Docs, Sound Kit, pp22-498
- [Sound getVolume: &oldVolumeLeft:&oldVolumeRight];
-
- #ifdef DEBUG
- fprintf(stderr,"Old volume L=%f R=%f, New Volume =%f\n",
- oldVolumeLeft, oldVolumeRight, [global volume]);
- #endif
-
- alarmFree = FALSE;
-
- // if( index(alarmSound, '/') == (char *) 0)
- soundfile = [Sound findSoundFor: alarmSound];
- // else
- // soundfile = [Sound newFromSoundfile: alarmSound];
-
- if( soundfile != nil)
- {
- [soundfile setDelegate: self];
- if( [global volume] >= 0)
- [Sound setVolume: [global volume]:
- [global volume]];
- error = [soundfile play];
- if( error != 0)
- {
- fprintf(stderr,"Cassandra: "
- "There was an error %d (%s)"
- " playing the alarm sound: %s.\n",
- error, SNDSoundError(error),
- alarmSound);
- alarmFree = TRUE;
- // Restore old volume
- [Sound setVolume: oldVolumeLeft :
- oldVolumeRight];
- }
- }
- else
- {
- fprintf(stderr,
- "%s: Couldn't find the alarm sound <%s>."
- "Substituting with obnoxious system beep.\n",
- PROGNAME, alarmSound);
- NXBeep();
- alarmFree = TRUE;
- }
- return self;
- }
- - hadError : sender
- {
- char errorString[200];
- int error = [[sender soundBeingProcessed] processingError];
-
- sprintf(errorString,
- "Error #%d (%s) occured while playing the alarm sound <%s>.\n",
- error, SNDSoundError(error),
- [[sender soundBeingProcessed] name]);
-
- NXRunAlertPanel("Alarm Error",errorString,
- "Oh well...",NULL,NULL);
-
- [self nextSnoozeAlarm];
- [self queueDidChange: self];
-
- // Restore old volume
- [Sound setVolume: oldVolumeLeft: oldVolumeRight];
- alarmFree = TRUE;
- [soundfile free];
-
- return self;
- }
-
-
- - didPlay: sender
- {
-
- #ifdef DEBUG
- fprintf(stderr,"Alarm Freed! Restoring volume to %f and %f\n",
- oldVolumeLeft, oldVolumeRight);
- #endif
-
- // If the alarm panel is invisible, it must mean the user
- // meant for this to be a one shot deal, thus alert
- // Cassandra that the queue changed so that it can update
- // the alarm timers and overview window
- if( ![alarmPanel isVisible])
- [self queueDidChange: self];
-
-
- [snoozeButton setEnabled : FALSE];
- alarmFree = TRUE;
- [soundfile free];
-
- // Restore old volume
- [Sound setVolume: oldVolumeLeft: oldVolumeRight];
-
- return self;
- }
-
- - nextSnoozeAlarm
- {
- EFileLink here;
- Event *ev;
-
- ev = [Event newAt:[global eventFile]];
- [ev firstEvent]; /* Read the first event */
-
- here = [ev present];
- snooze = 0; /* Initialize it to a good number, ie. nothing */
-
- if( [ev snoozeNo] > 0)
- {
- struct tm next;
-
- #ifdef DEBUG
- fprintf(stderr,"Snooze %d times with "
- "intervals of %d minutes.\n\n",
- [ev snoozeNo], [ev snoozeInt]);
- #endif
-
- /* Decrease the number of snooze events by 1 */
- [ev setSnoozeNo : ([ev snoozeNo] -1)];
-
- /* Add the snooze interval to minutes */
- /* Don't worry about overflow */
- /* insertEvent can handle that */
- next = *[ev time];
- next.tm_min += [ev snoozeInt];
-
- /* Set event parameters so that the inserted one gets nixed */
- /* properly when its time is due */
- [ev setDestroy :1];
- [ev setAnniversary :0];
- [ev setPriority :1];
- [ev setTime: &next];
-
- /* Set the snooze marker so we know which event to nix later */
- /* and insert the new event */
- snooze = [ev insertEvent];
-
- // Turn the queueModified flag on so that the next
- // timerUpdate will re-read the queue for the first event
- queueModified = TRUE;
-
- [ev free];
- }
- [self alarmReset: self];
- return self;
- }
-
-
- - alarmSnooze : sender
- {
- #ifdef DEBUG
- fprintf(stderr,"Alarm snoozeing....\n");
- #endif
-
- if( [alarmPanel isVisible])
- {
- if( !alarmFree)
- {
- [soundfile stop];
- [soundfile free];
- alarmFree = TRUE;
- }
- [alarmPanel close];
-
- [self queueDidChange: self];
-
- // Restore old volume
- [Sound setVolume: oldVolumeLeft: oldVolumeRight];
- }
- return self;
- }
-
- - alarmStop: sender
- {
- if( [alarmPanel isVisible])
- {
- #ifdef DEBUG
- fprintf(stderr,"Alarm stopping.\n");
- fprintf(stderr,"Restoring volume to %f and %f\n",
- oldVolumeLeft, oldVolumeRight);
- #endif
-
- if( !alarmFree)
- {
- [soundfile stop];
- [soundfile free];
- alarmFree = TRUE;
- }
- [alarmPanel close];
-
- // Restore old volume
- [Sound setVolume: oldVolumeLeft: oldVolumeRight];
-
- if( snooze > 0 )
- {
- id ev;
-
- ev = [Event newAt:[global eventFile]];
- [ev deleteEvent: snooze];
- [ev free];
- snooze = 0;
- }
-
- [self queueDidChange: self];
- }
- return self;
- }
-
-
- // This is connected to the Reset/Cancel Button on the main menu->
- // Modify Events submenu.
- - resetCancel : sender
- {
- Event *ev;
-
- ev = [Event newAt:[global eventFile]];
- [ev firstEvent]; /* Read the first event */
-
- if( [ev present] == 0)
- {
- NXRunAlertPanel("Alert",
- "You cannot reset/cancel the next event "
- "since there are no events...",
- "OK", NULL, NULL);
- [ev free];
- return self;
- }
-
- if( NXRunAlertPanel( "Alert",
- "This will reset the next event. "
- "Are you sure you want to do this?",
- "Do it","Cancel",NULL) == 1)
- {
- [self alarmReset:self];
- [self queueDidChange: self];
- }
-
- [ev free];
- return self;
- }
-
- // Actually reset the next event.
- // Delete the first event in the queue. Log it if it has a high
- // enough priority. Check if it is an anniversary event, and handle
- // that.
- - alarmReset: sender
- {
- Event *ev;
- FILE *fd;
- int temp;
- static struct tm lastEventTime;
-
- ev = [Event newAt:[global eventFile]];
-
- [ev firstEvent]; /* Read the first event */
-
- if( [ev priority] >= [global lowPriority] && [ev present] != 0)
- {
- char errormsg[128];
-
- // Ok, we are writing to the event log, just to be sure,
- // let's tell the event log object to save itself.
- [eventLog save];
-
- sprintf(errormsg, "Fatal error while creating "
- "the log file %s", [global eventLogFile]);
-
- // Check to make sure it exists, if it does not
- // we have to create it and stick a header on it
- if( access( [global eventLogFile], F_OK ) == -1)
- {
- if( ( fd = fileOpen( (char *)[global eventLogFile],
- "a", errormsg)) != NULL)
- {
- fprintf(fd, "{\\rtf0\\ansi"
- "{\\fonttbl\\f0\\fswiss "
- "Helvetica;}\n}\n");
- fclose( fd);
- }
- else
- fprintf(stderr,"%s: Couldn't create logfile\n",
- PROGNAME);
- }
-
-
- sprintf(errormsg, "Fatal error while appending to "
- "the log file %s", [global eventLogFile]);
-
- if( ( fd = fileOpen((char *) [global eventLogFile],"a",
- errormsg)) != NULL)
- {
- fseek(fd, -2, SEEK_END); // Remove bracket from end
- if( lastEventTime.tm_mday != timeNow()->tm_mday ||
- lastEventTime.tm_mon != timeNow()->tm_mon ||
- lastEventTime.tm_year != timeNow()->tm_year)
- {
- fprintf(fd, "\\par\\f0\\b %s\\par\n",
- ascMyDate([ev time]));
- lastEventTime = *timeNow();
- }
-
- if( [ev priority] > [global highPriority])
- fprintf(fd, "\\f0\\b ");
- else
- fprintf(fd, "\\f0\\b0 ");
-
- if( [global militaryTime])
- fprintf(fd, "\t%2d:%02d\t%s"
- "\\par\n",
- [ev hour], [ev min],
- [ev message]);
- else
- {
- temp = [ev hour];
-
- if( temp > 12 )
- temp -= 12;
- if( temp == 0 )
- temp = 12;
-
- fprintf(fd, "\t%2d:%02d %s\t%s"
- "\\par\n",
- temp,
- [ev min],
- ([ev hour]>11)?"pm":"am",
- [ev message]);
- }
- fprintf(fd, "}");
- fclose(fd);
- [eventLog update];
- }
- else
- fprintf(stderr,"couldn't open file\n");
-
- }
- else
- {
- #ifdef DEBUG
- fprintf(stderr,"Not high enough priority to log.\n");
- #endif
- }
-
- [ev murderEvent: [ev present]]; // Kill/delete/anniverserate event
-
- // Turn the queueModified flag on so that the next timerUpdate
- // will re-read the queue for the first event
- [self queueDidChange: self];
-
- [ev free];
- return self;
- }
-
- // Message queueDidChange:sender
- // Received if the event queue has changed in any fashion.
- // Tells other objects to update themselves to respond to this change.
- - queueDidChange: sender
- {
-
- // Notify the overview window object that the queue has changed
- [overview queueDidChange:self];
-
- // Notify the Today window to update itself just in case
- [today update];
-
- // Notify the Week window to update itself just in case
- [week update];
-
- // Update the clockView if necessary
- [self updateClockViewMessage: self];
-
- // Turn the queueModified flag on so that the next timerUpdate
- // will re-read the queue for the first event
- queueModified = TRUE;
-
- // Check the next alarm, now that the flag has been set.
- [self timerUpdate:self];
-
- // And reschedule the timer entry for the next alarm.
- // Give the user ten seconds to react
- [[self stopAlarmTimedEntry] startAlarmTimedEntry: 10.0];
-
- return self;
- }
-
- - updateClockViewMessage: sender
- {
- static char buf1[80], buf2[80];
- extern const char *shortMonths[12];
-
- //Check to see if we are using the snazzy digital clock, if we are
- // then we want to snarf off the first event and pipe it to Clock
- if( [global clockType] == CLOCK_DIGITAL)
- {
- Event *ev;
- int hour;
- char *suffix;
-
- ev = [Event newAt:[global eventFile]];
- [ev firstEvent]; // Read in the first event
-
- hour = [ev hour];
- if( ![global militaryTime])
- {
- if( hour >= 12 )
- {
- suffix = "p";
- hour -= 12;
- }
- else
- suffix = "a";
-
- if( hour == 0 )
- hour = 12;
- }
- else
- suffix = "";
-
- sprintf(buf1,"%2d:%02d%s %s %d", hour, [ev min], suffix,
- shortMonths[ [ev mon] ], [ev mday]);
-
- strncpy(buf2, [ev message], 20);
- [clockView setMessage: buf1: buf2];
- [ev free];
- }
- return self;
- }
-
- - defaultsDidChange: sender
- {
- const char *str;
-
- #ifdef DEBUG
- fprintf(stderr,
- "Defaults did change... App compensating.\n");
- #endif
-
- [overview defaultsDidChange: self];
- [today defaultsDidChange: self];
- [week defaultsDidChange: self];
-
- // Read the ShowSeconds default and process it.
- [clockView setShowSecondsToBool: [global showSeconds]];
- [clockView setShowDateToBool: [global showDate]];
- [clockView setClockTypeToInt: [global clockType]];
- [clockView setMilitaryTimeToBool: [global militaryTime]];
- [self updateClockViewMessage: self];
-
- // Read the FaceBitmap default and process that.
- str = [global clockfaceBitmapName];
- [clockView setClockFaceToBitmapNamed:(str && str[0] ? str : NULL)];
-
- saveScreen = [global saveScreen];
-
- return self;
- }
-
-
- // Message timerUpdate: sender
- // This checks the present alarm and the first event of the queue and compares
- // them. If the event at the very front is equal to or greater
- // than the present time, then send off messages turning on the alarm system.
- - timerUpdate :sender
- {
- static struct tm nextAlarmTime;
- static int presentEventNumber;
- static BOOL backlog = NO;
-
- // Check to see if the queue has been modified/changed since the last
- // time we read. If it has, we have to re-read the first event in
- // since its time may have changed.
- if( queueModified)
- {
- Event *ev;
-
- ev = [Event newAt:[global eventFile]];
-
- #ifdef DEBUG
- fprintf(stderr,"Queue modified/new. "
- "Re-reading event.\n");
- #endif
-
- [ev firstEvent]; // Read in the first event
-
- /* Remember its number (place) in the queue */
- presentEventNumber = [ev present];
-
- /* and copy down the time at which it will occur */
- nextAlarmTime = *[ev time];
-
- queueModified = FALSE; // Reset the flag,
- [ev free]; // and tidy up
- }
- else
- {
- // If the list was not modified, we can stick with the
- // information we
- // already have in presentEventNumber and nextAlarmTime
- #ifdef DEBUG
- fprintf(stderr,
- "Queue not modified. Skipping re-read.\n");
- #endif
- }
-
- /* How many more seconds until the event? */
- if( presentEventNumber > 0) // Check if we're on the first event
- secondsUntilEvent = secondsBetween( (struct tm *)
- timeNow(), &nextAlarmTime );
- else
- secondsUntilEvent = 60*60*4; // Four hours
-
- #ifdef DEBUG
- fprintf(stderr, "Time now = %s.\n",
- ascMyTime((struct tm*) timeNow(),
- SEC, [global militaryTime]));
- fprintf(stderr, "Event #%d's time = %s. \n"
- "secondsUntilEvent = %6.1f sec. (%6.1f min.)\n",
- presentEventNumber,
- ascMyTime( &nextAlarmTime,SEC, [global militaryTime]),
- secondsUntilEvent, secondsUntilEvent/60);
- #endif
-
- /* If it looks like the user has backlogged a lot of events, ask */
- /* her or him if she or he wants to clear all of the until today */
- if(secondsUntilEvent < (double) -(24*60*60) && presentEventNumber >0)
- {
- [NXApp unhide: self];
- if(backlog == YES || NXRunAlertPanel("Backlog Warning",
- "You have backlogged more than a day's "
- "worth of events. "
- "Would you rather clear all of them?",
- "Yes","No",NULL) == 1)
- {
- Event *ev;
- ev = [Event newAt:[global eventFile]];
-
- backlog = YES;
-
- do
- {
- [self alarmReset:self];
- [ev firstEvent];
- }
- while( secondsBetween((struct tm *) timeNow(),
- [ev time]) < 0 && [ev present] > 0);
-
- [ev free];
- [self queueDidChange:self];
- return self;
- }
- else
- backlog = NO;
- }
-
-
- /* If the event's time has come and it isn't a bogus event */
- /* (0 or below are ignored) then start the alarm */
- if( secondsUntilEvent <= 0 && presentEventNumber > 0)
- {
- [self alarmStart:self];
- }
- else
- {
- // OK, then let us start the bloody timer again
- [self startAlarmTimedEntry: secondsUntilEvent];
- }
- return self;
- }
-
- // ===================================
- // Timer Routines
- // ===================================
- // These handle the timer object
- // for alarm control.
- // Borrowed mostly off the Animator object.
-
- void checkAlarm(teNum, now, cassandra)
- DPSTimedEntry teNum;
- double now;
- id cassandra;
- {
- [cassandra stopAlarmTimedEntry];
- [cassandra timerUpdate:cassandra];
- }
-
-
- - startAlarmTimedEntry:(double) fireWhen
- {
- double fireIn;
-
- if( fireWhen > 0.0)
- fireIn = fireWhen;
- else
- {
- if (fireWhen = NOW || fireWhen < 0.0)
- fireIn = 0.0; // Fire as soon as possible!
- else
- {
- fireIn = secondsUntilEvent;
- if( fireIn > MAXSECONDS )
- fireIn = (double) MAXSECONDS;
- }
- }
-
- #ifdef DEBUG
- fprintf(stderr,"Starting alarmTE in %5.2f seconds. "
- "(%d min. %d sec.)\n", fireIn,
- ((int) fireIn / 60), ((int)fireIn % 60));
- #endif
-
- alarmTE = DPSAddTimedEntry(fireIn, &checkAlarm,
- self, NX_MODALRESPTHRESHOLD);
-
- return self;
- }
-
- - stopAlarmTimedEntry
- {
- #ifdef DEBUG
- fprintf(stderr,"Stopping alarmTE.\n");
- #endif
- if( alarmTE != NULL)
- DPSRemoveTimedEntry (alarmTE);
-
- alarmTE = NULL;
- return self;
- }
-
- - tick:sender;
- {
- int ad =0;
- int evs;
- static dimmed = FALSE;
- static minuteNow;
-
- [overview timeUpdate:self];
- [today timeUpdate: self];
-
- // Check things that only needed to be checked periodically.
- if( minuteNow != timeNow()->tm_min)
- {
-
- if( timeNow()->tm_mday != now.tm_mday)
- {
- [today update];
- [overview monthUpdate: self];
- [week update];
- now = *timeNow();
- }
-
-
- if( saveScreen )
- {
- // Check state of autodimming
- evs = open( "/dev/evs0", O_RDONLY);
- ioctl(evs, EVSIOCADS, &ad);
- close(evs);
-
- if( ad )
- {
- if( dimmed == FALSE)
- [self screenDimmed: self];
- dimmed = TRUE;
- }
- else
- {
- if( dimmed == TRUE)
- [self screenUndimmed: self];
- dimmed = FALSE;
- }
- }
- }
- return self;
- }
-
- // The screen has dimmed. Call whatever program the user wants.
- - screenDimmed: sender
- {
- static char command[128];
-
- sprintf(command, "%s&", [global screenSaver]);
-
- #ifdef DEBUG
- fprintf(stderr,"%s: System autodimmed w/ <%s>\n",
- PROGNAME, [global screenSaver]);
- NXBeep(); NXBeep();
- #endif
-
- system( command );
- return self;
- }
-
- - screenUndimmed: sender
- {
- #ifdef DEBUG
- fprintf(stderr,"%s: Screen undimmed.\n", PROGNAME);
- #endif
-
- return self;
- }
-
- - global { return global; }
- @end
-
-